//----------------------------------------------------------------------------
//  ,-.
// /_\___ ,   Ninja Framework
// '  ___\    (C) Riccardo Capra - http://riccar.do
//  //   \\
//----------------------------------------------------------------------------
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
//----------------------------------------------------------------------------

#ifndef NJ_DEBUG_LOCKLESS_CIRCULAR_BUFFER_H
#	define NJ_DEBUG_LOCKLESS_CIRCULAR_BUFFER_H

#	include "NjNinjaSyncLib.h"
#	include "NjFundamentalMacros.h"
#	include "NjFundamentalTypes.h"
#	include "NjAtomic.h"

	/// \brief Implements a fast lockless circular buffer to be used for debugging purposes
	/// \param tEntry The type used as entry
	/// \param uSize The circular buffer size
	template<class tEntry, NjUint uSize>
	class NjDebugLocklessCircularBuffer
	{
	public:
		/// \brief Default constructor for NjDebugLocklessCircularBuffer
		NjDebugLocklessCircularBuffer();
		NJ_TRIVIAL_DESTRUCTOR(NjDebugLocklessCircularBuffer);

		/// \brief Returns an entry that can be filled in by the caller
		tEntry * Record();

	private:
		/// \brief The real entry type used in the implementation
		class Entry : public tEntry
		{
		public:
			NJ_TRIVIAL_DEFAULT_CONSTRUCTOR(Entry);
			NJ_TRIVIAL_DESTRUCTOR(Entry);

			/// \brief This is the progressive number of the stored entry
			///
			/// An entry at position \em uIndex must have \em m_uCounter equal to \em uIndex+uSize*uFactor
			/// where \em uFactor is zero or a positive integer
			NjUint m_uCounter;

			NJ_DISABLE_COPY(Entry);
		};

		/// \brief A progressive counter
		NjAtomic<NjUint> ms_kCounter;

		/// \brief The entries stored in the circular buffer
		Entry ms_aEntries[uSize];

		NJ_DISABLE_COPY(NjDebugLocklessCircularBuffer);
	};

#	include "NjDebugLocklessCircularBuffer_inline.h"

#endif // NJ_DEBUG_LOCKLESS_CIRCULAR_BUFFER_H
